package main

import "fmt"

/*
【1】defer关键字的作用：
在函数中，程序员经常需要创建资源，为了在函数执行完毕后，及时的释放资源，Go的设计者提供defer关键字

【2】在golang中,程序遇到 defer 关键字,不会立即执行 defer 后的语句,而是将defer后的语句压入一个栈中,然后执行函数后面的语句
栈的特点是: 先进后出
		  在函数执行完毕以后,从栈中取出语句开始执行,按照先进后出的规则执行语句

【3】发现：遇到defer关键字，会将后面的代码语句压入栈中，也会将相关的值同时拷贝入栈中，不会随着函数后面的变化而变化。

【4】defer应用场景：(资源释放,IO)
比如你想关闭某个使用的资源，在使用的时候直接随手defer，因为defer有延迟执行机制（函数执行完毕再执行defer压入栈的语句），
所以你用完随手写了关闭，比较省心，省事
*/

//闭包：返回的匿名函数+匿名函数以外的变量num
func main() {

	fmt.Println(add1(30, 60))
	fmt.Println()
	fmt.Println(add2(30, 60))
	fmt.Println()
	fmt.Println(testMsg())

}

func add1(num1 int, num2 int) int {
	//输出:
	//sum= 190
	//num2= 110
	//num1= 80
	//190
	num1 += 50
	num2 += 50
	defer fmt.Println("num1=", num1)
	defer fmt.Println("num2=", num2)
	var sum int = num1 + num2
	fmt.Println("sum=", sum)
	return sum
}

func add2(num1 int, num2 int) int {
	//遇到defer关键字，会将后面的代码语句压入栈中，也会将相关的值同时拷贝入栈中
	//所以输出还是: num2= 60, num1= 30; 而不是 num2= 110, num1= 80
	//sum= 190
	//num2= 60
	//num1= 30
	//190
	defer fmt.Println("num1=", num1)
	defer fmt.Println("num2=", num2)
	num1 += 50
	num2 += 50
	var sum int = num1 + num2
	fmt.Println("sum=", sum)
	return sum
}

type msg struct {
	id   int
	code int
	text string
}

func testMsg() msg {
	orgMsg := &msg{
		id:   0,
		code: 404,
		text: "initialization",
	}
	defer fmt.Println("orgMsg1=", orgMsg)
	orgMsg.code = 200
	defer fmt.Println("orgMsg2=", orgMsg)
	return *orgMsg
}
